package storage.v1;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.WeakHashMap;

import com.onpositive.commons.platform.registry.IAdaptable2;
import com.onpositive.data.IPropertyConstants;
import com.onpositive.mediawiki.propertyparser.ParsedCategory;
import com.onpositive.mediawiki.propertyparser.ParsedDocument;
import com.onpositive.mediawiki.redirects.IRefsRedirector;
import com.onpositive.mediawiki.redirects.WikipediaRefsRedirector;
import com.onpositive.units.ParsedProperty;
import com.onpositive.units.ParsedValueSequence;
import com.onpositive.utils.IStringPoolProvider;
import com.onpositive.wikitemplate.TemplateInfoProvider;
import com.onpositive.wikitemplate.DefaultTemplateResolver;

public class ParserV2 {
	

	IValueExtractor[] extractors = { new PictureInfoExtractor(),
			new TextSectionsExtractor(), new ValuesExtractorV1(), new TableValueExtractor() } ;
		
	public ParsedDocument parseDocument( String documentContent, IParserProvider parserProvider, IAdaptable2 adaptable  )
	{
		
		if (documentContent==null)
			return null ;

		ParsedDocument pDoc = new ParsedDocument();
		
		for( IValueExtractor extractor : extractors )
			extractor.process( documentContent, pDoc, parserProvider, adaptable ) ;
		
		return pDoc ;				
	}
	
	public void parseDocument( String documentContent, IParserProvider parserProvider, IAdaptable2 adaptable, ParsedDocument pDoc  )
	{		
		if (documentContent==null)
			return ;
		
		for( IValueExtractor extractor : extractors )
			extractor.process( documentContent, pDoc, parserProvider, adaptable ) ;
	}
	
	private static IRefsRedirector redirector;
	private static WeakHashMap<String,String> refsRedirectionMap, nullRedirects ; 
	
	public static String redirect( String str ){
		
		String s0 = str.replace(' ', '_') ;
		if( redirector == null  )
			redirector = new WikipediaRefsRedirector() ;
		
		if( refsRedirectionMap == null )
			refsRedirectionMap = new WeakHashMap<String,String>() ;
		
		if( nullRedirects == null )
			nullRedirects = new WeakHashMap<String, String>();
		
		
		if( nullRedirects.get(s0) != null )
			return null ;
			
		String result = refsRedirectionMap.get(s0) ;
		if( result == null ){
			result = redirector.redirect(s0) ;
			
			if( result != null )
				refsRedirectionMap.put(s0, result) ;
			else
				nullRedirects.put(s0, "") ;			
		}
		
		if( result != null )
			result = result.replace('_', ' ') ;
				
		return result ;		
	}
	private static void disposeRefs() {
		redirector = null ;
		refsRedirectionMap = null ;
		nullRedirects = null ;
	}

	static HashSet<Character> listStartChars = new HashSet<Character>( Arrays.asList( new Character[]{' ', '*'})  ) ; 
	static public String killListStarts(String propValue)
	{
		int i = 0 ;
		int length = propValue.length();
		for( ; i < length && listStartChars.contains( propValue.charAt(i) )  ; i++ ) ;
		
		return propValue.substring(i) ;		
	}
	
	
	public void dispose(){		
		for( IValueExtractor extractor : extractors )
			extractor.dispose() ;
		
		disposeRefs() ;
	}


	static public String killRefs(String _propValue)
	{		
		String str = killComments(_propValue) ;
		int l = str.length() ;
		StringBuilder builder = new StringBuilder() ;		
		
		int l0 = "<ref".length() ;
		int prev = 0 ;
		for ( int i = str.indexOf("<ref") ; i >= 0 ; i = str.indexOf("<ref",prev) )
		{
			builder.append( str.substring( prev, i ) ); 
			i += l0 ;			
			for( ; i < l && Character.isWhitespace( str.charAt(i) ) ; i++  ) ;
			if( i >= l )
			{
				prev = l ; 
				break ;
			}
			char ch = str.charAt(i) ;
			int l1 ;
			if( ch == '>' ){
				prev = str.indexOf("</ref>",i) ;
				l1 = "</ref>".length() ;
			}
			else{
				prev = str.indexOf("/>",i) ;
				l1 = "/>".length() ;
			}			
			prev = prev < 0 ? l : prev + l1 ;
		}
		builder.append( str.substring(prev,l) ) ;
		str = builder.toString() ;
		
		str=str.replace(" />", "/>");
		str = killBreaks(str);
		str=str.replaceAll("<li>"," ");
		str=str.replaceAll("<li/>"," ");
		str=str.replaceAll("</li>"," ");
		
		str = str.replaceAll( "\\s{2,}"," " ) ;
		
		return str.trim();
	}

	static TemplateInfoProvider templateInfoProvider = new TemplateInfoProvider() ;
	static public String killTemplates(String str, TemplateInfoProvider extProvider )
	{
		if( extProvider == null )
			extProvider = templateInfoProvider ;
		
		ArrayList<Integer> iArr = new ArrayList<Integer>() ;
		
		int l = str.length() ;
		int level = 0 ;		
		for( int i = 0 ; i < l ; i++ )
		{
			if( str.startsWith("{{",i) )
			{
				iArr.add( i) ;
				iArr.add( 1) ;
				level++ ;				
				i++ ;
			}
			if( str.startsWith("}}",i) )
			{
				if( level > 0 )
				{
					iArr.add( i+2) ;
					iArr.add( 2) ;
					level-- ;
				}
				else if( iArr.size() == 0 )
				{
					iArr.add( i+2 ) ;
					iArr.add(-1) ;
				}
				else
					iArr.set( iArr.size()-2, i+2 ) ;

				i++ ;
			}			
		}
		if( iArr.size() == 0 )
			return str ;
		
		ArrayList<Integer> bounds = new ArrayList<Integer>() ;
		int i = 0 ;
		if( iArr.get(1) < 0 ){			
			bounds.add( iArr.get(0) ) ;
			i += 2 ;
		}
		else{
			bounds.add( 0 ) ;
		}
		try{
		while( i < iArr.size() )
		{
			int ind = iArr.get( i );
			if(  iArr.get( i+1 ) == 1 )
			{
				int j0 = ind + 2 ;
				int nextInd = i+2 < iArr.size() ? iArr.get( i+2 ) : str.length();
				for( ; Character.isWhitespace( str.charAt(j0) ); j0++ ) ;
				int j1 = j0 ;
				for( ; j1 < nextInd && !Character.isWhitespace( str.charAt(j1) ) && str.charAt(j1) != ':' && str.charAt(j1) != '|'; j1++ ) ;
				
				String templateName = str.substring(j0,j1) ;
				
				int _i = i ;
				i += 2 ;
				level = 1 ;
				while( i < iArr.size() && level > 0 )
				{
					if( iArr.get(i+1) == 1 )
						level++ ;
					if( iArr.get(i+1) == 2 )
						level-- ;
					i += 2;
				}
				
				if( extProvider.needToBeKilled( templateName ) )
				{					
					bounds.add( iArr.get(_i) ) ;
					bounds.add( iArr.get(i-2) )  ;					
				}
				else if( level > 0 )
				{					
					bounds.add( iArr.get(_i) ) ;
					bounds.add( l ) ;					
				}
				else
					i = _i + 2 ;
				
				continue ;
			}			
			i += 2 ;						
		}
		}
		catch( Exception e ){
			e.printStackTrace() ;
		}
			
			
		bounds.add( l ) ;
		
		StringBuilder builder = new StringBuilder() ;
		for( int k = 0 ; k < bounds.size() ; k += 2 )
			try{
				builder.append( str.substring( bounds.get(k), bounds.get(k+1) )) ;
			}catch( Exception e)
			{
				e.printStackTrace() ;
			}
		
		return builder.toString().replaceAll( "[ ]{2,}", " ") ;
	}

	public static String killBreaks(String propValue) {
		propValue=propValue.replaceAll("<br>"," ");
		propValue=propValue.replaceAll("<br/>"," ");
		propValue=propValue.replaceAll("<br />"," ");
		propValue=propValue.replaceAll("</br>"," ");
		return propValue;
	}
	
	public final static String[] delimeters = new String[]{",", "/", "&", "and", ";", ".", ParsedValueSequence.valueSeparator } ;// add "-" after links audit
	//public final static String[] extendedDelimeters = new String[]{",", "/", "&", "and", ";", "." } ;

	public static String turnBreaksToPoints(String propValue)
	{
		String[] breakStrings = new String[]{"<br>","<br/>", "<br />", "</br>"} ;
		ArrayList<Integer> replacementData = new ArrayList<Integer>( Arrays.asList( new Integer[]{-1,0,-1}) ) ;
		
		int l = propValue.length() ;
		
		int templDepth = 0, refDepth = 0 ;
		for( int i = 0 ; i < l ; i++ )
		{
			if( propValue.startsWith("{{", i )){
				templDepth++ ;
				continue ;
			}
			if( propValue.startsWith("}}", i )){
				templDepth-- ;
				continue ;
			}
			if( propValue.startsWith("[[", i )){
				refDepth++ ;
				continue ;
			}
			if( propValue.startsWith("]]", i )){
				refDepth-- ;
				continue ;
			}
			
			
			
			for( String brStr : breakStrings )
			{
				if( !propValue.startsWith(brStr , i )  )
					continue ;
				
				int lb, ub ;
				for( lb = i-1 ; lb >= 0 && Character.isWhitespace( propValue.charAt(lb) ) ; lb-- ) ;
				for( ub = i+brStr.length() ; ub < l && Character.isWhitespace( propValue.charAt(ub) ) ; ub++ ) ;
				
				int rank = -1 ;

				boolean includeLB = false, includeUB = false ;
				if( lb >= 0 ){
					for( int j = rank+1 ; j < delimeters.length ; j++ )
						if( propValue.substring(0,lb+1).endsWith( delimeters[j] ) )
						{
							rank = j ;
							includeLB = true ;
						}
				}
				else
					lb = 0 ;
				
				if(replacementData.size() != 0)
				{				
					int prevUb = replacementData.get( replacementData.size()-2 ) ;
					lb = lb < prevUb ? prevUb : lb ;
				}
				
				if( ub < l )
					for( int j = rank+1 ; j < delimeters.length ; j++ )
						if( propValue.startsWith( delimeters[j], ub ) )
						{
							rank = j ;
							includeUB = true ;
							i = ub + delimeters[j].length() ;
						}
				
				if( templDepth != 0 || refDepth != 0 )
					rank = delimeters.length ;
					
				replacementData.add( includeLB ? lb   : lb+1 ) ;
				replacementData.add( includeUB ? ub+1 : ub   ) ;
				replacementData.add( rank ) ;
				break ;
			}
		}
		replacementData.addAll( Arrays.asList( new Integer[]{ l, -1,-1 } ) ) ;
		
		StringBuilder builder = new StringBuilder() ;
		int blockSize = 3 ;
		for( int i = blockSize ; i < replacementData.size() - blockSize ; i += blockSize )
		{
			Integer ind0 = replacementData.get( i - blockSize + 1 );
			Integer ind1 = replacementData.get( i );
			Integer delimeterKind = replacementData.get( i + 2 );
			@SuppressWarnings("unused")
			boolean test = ind0 < 0 || ind1 > propValue.length() || ind0 > ind1 ;
			builder.append( propValue.substring( ind0, ind1 ).trim() ) ;
			
			if( delimeterKind >= 0 )
			{
				if( delimeterKind < delimeters.length ){
					builder.append( " " ) ;
					builder.append( delimeters[delimeterKind] ) ;
					builder.append( " " ) ;
				}
				else
					builder.append(" ") ;
			}
			else
				builder.append( "\n" ) ;			
		}
		Integer ind0 = replacementData.get( replacementData.size() - 2*blockSize + 1 );
		Integer ind1 = replacementData.get( replacementData.size() -   blockSize     );
		builder.append( propValue.substring( ind0, ind1 ).trim() ) ;

		String resultingString = builder.toString().trim();
		
		return resultingString;
	}
	public static String killComments(String str)
	{
		int l = str.length() ;
		StringBuilder builder = new StringBuilder() ;
		int prev = 0 ;
		for ( int i = str.indexOf("<!--") ; i >= 0 ; i = str.indexOf( "<!--", prev ) )
		{
			builder.append( str.substring(prev, i) ) ;
			i += "<!--".length() ;
			prev = str.indexOf("-->", i ) ;
			prev = prev < 0 ? l : prev + "-->".length() ;			
		}
		builder.append( str.subSequence(prev, l) ) ;
		
		String result = builder.toString() ;
		prev = result.indexOf("-->") ;
		if( prev >= 0 )
			result = result.substring( prev + "-->".length() ) ;
		
		return result ;
	}
	
	public static String killWikiRefsLeaveCaptions( String s )
	{
		String line = s ;
		//get rid of [[knot (unit)|kn]] and [[mph]] -like stuff
		line = line.replaceAll("(\\[\\[)(([^\\[\\]]*)(\\|)|)([^\\[\\]]*)(\\]\\])", "$5");
		//line = line.replaceAll("(\\{\\{)([^\\{\\}]*)(\\|)([^\\{\\}]*)(\\}\\})", "$4" ) ;
		return line.trim() ;
	}
	public static String killWikiRefsLeaveRefs( String s )
	{
		String line = s ;
		//get rid of [[knot (unit)|kn]] and [[mph]] -like stuff
		line = line.replaceAll("(\\[\\[)([^\\[\\]\\|]*)([\\|]){0,1}([^\\]\\]]*)(\\]\\])", "$2");
		line = line.replaceAll("(\\{\\{)([^\\{\\}]*)(\\|)([^\\{\\}]*)(\\}\\})", "$4" ) ;
		return line.trim() ;
	}
	private static final String noBreakSpaceString = "" + (char)8239 ;
	
	public static String killNoBreakSpace( String str ){
		return str.replace( noBreakSpaceString , "") ;
	}
	
	
	public static String killPictures(String line) {
		
		String result = line ;
		ArrayList<Integer> bounds = new ArrayList<Integer>() ;
		StringBuilder builder = new StringBuilder() ;
		for( String keyWord : PictureInfoExtractor.picKeys )
		{
			bounds.clear() ;
			bounds.add(0) ;
			for( int ind = result.indexOf( keyWord ) ; ind >= 0 ; ind = result.indexOf( keyWord, ind ) )
			{
				int start = result.lastIndexOf("[[", ind ) ;
				if( start < 0 ){
					ind++ ;
					continue ;
				}
				
				boolean good = true ;
				for( int i = start + 2 ; i < ind ; i++ )
					if( !Character.isWhitespace( result.charAt(i) ) )
						good = false ;
				
				if( !good ){
					ind++ ;
					continue ;
				}
				
				int weight = 1 ;
				int end = -1;
				int i ;
				for( i = start + 2 ; i < result.length() ; i++ )
				{
					if( result.startsWith("[[",i) )
					{
						weight++ ;
					}
					if( result.startsWith("]]",i) )
					{
						weight-- ;
						if( weight == 0 )
						{
							end = i + 2 ;
							bounds.add( start ) ;
							bounds.add( end ) ;
							ind = end ;
							break ;
						}
					}
				}
				if( i >= result.length() )
					ind++ ;
			}			
			bounds.add( result.length() ) ;
			
			builder.delete( 0,  builder.length() ) ;
			for( int i = 0 ; i < bounds.size() ; i += 2 )
				builder.append( result.substring(bounds.get(i), bounds.get(i+1) ) ) ;
			
			result = builder.toString() ;
		}
		return result ;
	}
	
	
	

}
